﻿namespace Navigant.Model.Custodians
{
    public class CustodianName
    {
        #region Constants

        private static class Constants
        {
            public const char CommaSeparator = ',';
            public const char SpaceSeparator = ' ';
        }

        #endregion

        #region Private Fields

        private string firstName;
        private string middleName;
        private string lastName;
        private string fullName;

        #endregion

        #region Constructors

        public CustodianName(string fullName)
        {
            if (fullName == null) fullName = string.Empty;
            this.fullName = fullName.Trim();

            if (this.fullName == string.Empty)
            {
                this.SetEmpty();
                return;
            }

            if (this.fullName.IndexOf(Constants.CommaSeparator) == -1 &&
                this.fullName.IndexOf(Constants.SpaceSeparator) == -1)
            {
                this.firstName = this.fullName;
                this.middleName = string.Empty;
                this.lastName = string.Empty;
                return;
            }

            this.ParseFullName();
            this.FormatFullName();
        }

        public CustodianName(string firstName, string middleName,
            string lastName)
        {
            this.firstName = (firstName == null ? string.Empty : firstName.Trim());
            this.middleName = (middleName == null ? string.Empty : middleName.Trim());
            this.lastName = (lastName == null ? string.Empty : lastName.Trim());
            this.FormatFullName();
        }

        #endregion

        #region Private Methods

        private void ParseFullName()
        {
            char separator = Constants.SpaceSeparator;
            if (this.fullName.IndexOf(Constants.CommaSeparator) > -1)
            {
                separator = Constants.CommaSeparator;
            }

            string[] parsedFullName = this.fullName.Split(separator);

            // Examples:  
            // 1.  McCarthy, Tim D.
            // 2.  Timothy D. McCarthy
            // 3.  Tim McCarthy

            if (parsedFullName.Length > 1)
            {
                if (separator == Constants.CommaSeparator)
                {
                    this.lastName = parsedFullName[0].Trim();

                    // parse for the middle name or initial
                    if (parsedFullName[1].Trim().IndexOf(Constants.SpaceSeparator) > -1)
                    {
                        this.firstName = parsedFullName[1].Trim().Split(Constants.SpaceSeparator)[0];
                        this.middleName = parsedFullName[1].Trim().Split(Constants.SpaceSeparator)[1];
                    }
                    else
                    {
                        this.firstName = parsedFullName[1].Trim();
                        this.middleName = string.Empty;
                    }
                }
                else
                {
                    this.firstName = parsedFullName[0].Trim();

                    // parse for the middle name or initial
                    if (parsedFullName.Length > 2)
                    {
                        this.middleName = parsedFullName[1].Trim();
                        this.lastName = parsedFullName[2].Trim();
                    }
                    else
                    {
                        this.middleName = string.Empty;
                        this.lastName = parsedFullName[1].Trim();
                    }
                }
            }
        }

        private void FormatFullName()
        {
            if (this.middleName.Length > 0)
            {
                this.fullName = string.Format("{0}, {1} {2}",
                    this.lastName, this.firstName, this.middleName);
            }
            else
            {
                this.fullName = string.Format("{0}, {1}",
                    this.lastName, this.firstName);
            }
        }

        private void SetEmpty()
        {
            this.firstName = string.Empty;
            this.middleName = string.Empty;
            this.lastName = string.Empty;
            this.fullName = string.Empty;
        }

        #endregion

        #region Properties

        public string FirstName
        {
            get { return this.firstName; }
        }

        public string MiddleName
        {
            get { return this.middleName; }
        }

        public string LastName
        {
            get { return this.lastName; }
        }

        public string FullName
        {
            get { return this.fullName; }
        }

        public override string ToString()
        {
            return this.fullName;
        }

        #endregion

        #region Equality Tests

        public override bool Equals(object custodianName)
        {
            return custodianName != null
                && custodianName is CustodianName
                && this == (CustodianName)custodianName;
        }

        public override int GetHashCode()
        {
            return this.firstName.GetHashCode() & 
                this.middleName.GetHashCode() & 
                this.lastName.GetHashCode();
        }

        public static bool operator ==(CustodianName name1,
            CustodianName name2)
        {
            // check for both null (cast to object or recursive loop)
            if ((object)name1 == null && (object)name2 == null)
            {
                return true;
            }

            // check for either of them == to null
            if ((object)name1 == null || (object)name2 == null)
            {
                return false;
            }

            if (name1.FirstName != name2.FirstName ||
                name1.MiddleName != name2.MiddleName || 
                name1.LastName != name2.LastName)
            {
                return false;
            }

            return true;
        }

        public static bool operator !=(CustodianName name1,
            CustodianName name2)
        {
            return (!(name1 == name2));
        }

        #endregion

        #region Static Methods

        public static CustodianName Empty()
        {
            return new CustodianName(string.Empty);
        }

        #endregion
    }
}
